Proxy pattern
代理模式为另一个对象提供一个代理对象以控制对这个对象的访问,被代理的对象可以是远程对象、创建开销大的对象或者需要安全控制的对象。
远程代理
远程代理即是我们希望通过调用一个本地对象,然后其能将每个请求转发到远程对象上进行。换句话说,客户对象意味它调用的是远程服务上的方法,实际上是代理对象假装有客户要调用的方法,真正执行方法的在远程的对象。
通过Java RMI我们可以简单实现远程调用,而无需处理细节的网络通信。
使用Java RMI的具体步骤为:
- 创建远程接口
- 实现远程接口的类Impl(main方法需要注册到RMI中)
- 使用Java rmic生成Impl的stud和skeleton,也就是客户和服务的辅助类。
- 在远程机器上启动RMI registry(倾听Impl的注册)
- 运行主方法(可以是启动类)将Impl注册到RMI服务上。
- 客户端调用Naming方法取得stub对象。
- 客户调用哦该stub方法,就像stub就是真正的服务对象一样。
服务端实现:
1 | public interface GumballMachineRemote extends Remote { |
1 | public interface State extends Serializable { |
1 | public class GumballMachine |
在RMI registry中注册
1 | public class GumballMachineTestDrive { |
客户端
1 | public class GumballMonitor { |
1 | public class GumballMonitorTestDrive { |
虚拟代理
远程代理可以作为另一个JVM上对象的本地代表。调用代理的方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再有代理将结果转给客户。
而虚拟代理通常作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求委托给对象。
比如我们需要创建一个CD封面对象,这个封面图片需要从网上下载。在下外完成前,我们最好也显式一些内容,这时我们就可以使用虚拟代理。
- ImageProxy首先创建一个ImageIcon,然后开始从网络上加载图像。
- 在加载过程中,ImageProxy显式”加载中…”
- 当图像加载完毕,ImageProxy把所有方法掉用委托给真正的ImageIcon。
1 | class ImageProxy implements Icon { |
1 | class ImageComponent extends JComponent { |
1 | public class ImageProxyTestDrive { |
使用Java API代理实现保护代理
Java在java.lang.reflect包中有自己的代理支持,利用哦该这个包我们可以在运行时动态的创建一个代理类,实现一个或多个接口,并将方法的调用转发到我们所指定的类。因为实际的代理是在运行时创建的,所以这个技术称为动态代理。
我们不需要自己创建Proxy类,也不能往里面添加代码。我们希望处理代码应该放在InvocationHandler中。InvocationHandler的工作是响应代理的任何调用,可以认为是代理收到方法调用后实际执行请求的对象。
假设我们正在实现一个信息管理服务,我们希望当前用户可以更改自己的基本信息,但不是不能更改自己的客观信息,同时其他用户也不能更改当前用户的基本信息。
1 | public interface PersonBean { |
这时我们可以为PersonBean创建动态代理,以过滤对这个类的请求:
- 创建InvocationHandler(如果有多种模式,需要创建多个,这里我们分为两类,操作用户是用户本人或是其他人,所以需要两个InvocationHandler)。
- 写代码创建动态代理。
- 利用适当的代理保证PersonBean对象,并将这个代理提供给客户,而不是对象本身。
1 | public class OwnerInvocationHandler implements InvocationHandler { |
1 | public class NonOwnerInvocationHandler implements InvocationHandler { |
1 | public class MatchMakingTestDrive { |